<?php

namespace App\Http\Controllers\Laravel\Queue;

use App\BCAM\CMVariable\CMVariable;
use App\Jobs\FailQueue;
use App\Jobs\LongQueue;
use App\Jobs\MyQueue;
use Carbon\Carbon;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class LabController extends Controller
{
    //
    public function main(){
        //字符串输出格式: 2017-09-19 14:16:46
        echo Carbon::now()->addMinutes(10);
        //返回一个对象Carbon对象
        CMVariable::compareRes(Carbon::now()->addMinutes(10));
        //如果是以mysql为驱动,可以在jobs中看见数据
        //绝对时间和相对时间都可以 <-错的
        /**
         * {"displayName":"App\\Jobs\\MyQueue","job":"Illuminate\\Queue\\CallQueuedHandler@call","maxTries":null,"timeout":null,"data":{"commandName":"App\\Jobs\\MyQueue","command":"O:16:\"App\\Jobs\\MyQueue\":4:{s:6:\"\u0000*\u0000job\";N;s:10:\"connection\";N;s:5:\"queue\";N;s:5:\"delay\";O:13:\"Carbon\\Carbon\":3:{s:4:\"date\";s:26:\"2017-09-21 21:14:03.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:13:\"Asia\/Shanghai\";}}"}}
         */
        //辅助函数 dispatch 需要的唯一参数就是该任务的实例
        dispatch((new MyQueue())->delay(Carbon::now()->addSeconds(10)));//???为什么可以成功
        /**
         * {"displayName":"App\\Jobs\\MyQueue","job":"Illuminate\\Queue\\CallQueuedHandler@call","maxTries":null,"timeout":null,"data":{"commandName":"App\\Jobs\\MyQueue","command":"O:16:\"App\\Jobs\\MyQueue\":4:{s:6:\"\u0000*\u0000job\";N;s:10:\"connection\";N;s:5:\"queue\";N;s:5:\"delay\";i:10;}"}}
         */
        //有时候你可能想要延迟队列任务的执行，可以通过在任务实例使用 delay 方法。该方法由Illuminate\Bus\Queueable trait提供，已经自动添加在通过命令行生成的任务类中
        dispatch((new MyQueue())->delay(10));//注：Amazon SQS 的队列服务最长延时 15 分钟。
        /**
         * {"displayName":"App\\Jobs\\MyQueue","job":"Illuminate\\Queue\\CallQueuedHandler@call","maxTries":null,"timeout":null,"data":{"commandName":"App\\Jobs\\MyQueue","command":"O:16:\"App\\Jobs\\MyQueue\":4:{s:6:\"\u0000*\u0000job\";N;s:10:\"connection\";N;s:5:\"queue\";N;s:5:\"delay\";N;}"}}
         */
        dispatch((new MyQueue()));//???为什么可以成功
        CMVariable::compareRes(Carbon::now()->addSeconds(10));
        //dispatch((new MyQueue())->delay(0));
    }

    public function carbonQueue(){
        $carbon = Carbon::createFromFormat('Y-m-d H:i:s','2017-09-21 21:45:00');
        CMVariable::compareRes($carbon,date('Y-m-d H:i:s'));
        dispatch((new MyQueue())->delay($carbon));
    }

    public function dateTimeQueue(){
        /**
         * {"displayName":"App\\Jobs\\MyQueue","job":"Illuminate\\Queue\\CallQueuedHandler@call","maxTries":null,"timeout":null,"data":{"commandName":"App\\Jobs\\MyQueue","command":"O:16:\"App\\Jobs\\MyQueue\":4:{s:6:\"\u0000*\u0000job\";N;s:10:\"connection\";N;s:5:\"queue\";N;s:5:\"delay\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2017-09-21 22:16:00.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:13:\"Asia\/Shanghai\";}}"}}
         */
        $dateM = \DateTime::createFromFormat('Y-m-d H:i:s','2017-09-21 22:16:00');
        dispatch((new MyQueue())->delay($dateM));
    }

    /**
     * 分发到指定的队列
     * 通过推送任务到不同队列，你可以将队列任务进行“分类”，甚至根据优先级来分配每个队列的进程数。请注意，这并不意味着使用了配置项中那些不同的连接来管理队列，实际上只有单一连接会被用到。要指定队列，请在任务实例使用 onQueue 方法
     */
    public function onQueue(){
        $job = (new MyQueue())->onQueue('test2');
        dispatch($job);
    }

    /**
     *分发到指定的连接
     */
    public function onConnection(){
        //数据库中会插入队列
        $job = (new MyQueue())->onConnection('database');
        //2.运行队列监听命令
        //3.queue:listen 正常只会运行默认连接
        //要运行非默认连接 queue:listen database 亲测
        dispatch($job);
    }

    /**
     * 如果是俩个不同连接,但是同名队列,执行 --queue=name 会一起被监听吗?
     * 猜测:不会
     * 测试:
     */
    public function onSameName(){
        //访问前,先不要执行监听命令,查看数据库和redis数据
        //观察结果:两个连接各一条
        $job = (new MyQueue())->onConnection('database')->onQueue('myname');
        dispatch($job);
        $jobT = (new MyQueue())->onQueue('myname');//不指定连接的情况下,使用默认连接
        dispatch($jobT);
        //运行queue:listen --queue=myname
        //并不会执行mysql中的队列
    }

    /**
     * 最大失败此时/超时时间
     * 指定队列任务最大失败次数的一种实现方式是通过 Artisan 命令 --tries 切换：

    php artisan queue:work --tries=3
     * 不过，你还可以在任务类自身定义最大失败次数来实现更加细粒度的控制，如果最大失败次数在任务中指定，则其优先级高于命令行指定的数值：
     */
    public function tries(){

    }

    public function timeOut(){

    }

    /**
     * 同一时间执行运行, --queue=high,any high会先执行,反之,--queue=any,high any会先执行
     */
    public function highAndAnyName(){
        $dateM = \DateTime::createFromFormat('Y-m-d H:i:s','2017-09-23 20:18:00');
        //先插随便一个队列名称
        $jobT = (new MyQueue('any'))->onQueue('any')->delay($dateM);
        dispatch($jobT);
        //在插一个high
        $job = (new MyQueue('high'))->onQueue('high')->delay($dateM);
        dispatch($job);
    }

    /**
     * 让优先级高的队列定时时间晚于低优先级的执行时间,看是否优先级低的会等待已知N分钟时间后执行的队列
     */
    public function delayHigh(){
        $dateM = \DateTime::createFromFormat('Y-m-d H:i:s','2017-09-23 22:23:00');
        $jobT = (new MyQueue('any'))->onQueue('any')->delay($dateM);
        dispatch($jobT);
        $dateT = \DateTime::createFromFormat('Y-m-d H:i:s','2017-09-23 22:23:20');
        $job = (new MyQueue('high'))->onQueue('high')->delay($dateT);
        dispatch($job);
        //①如果第一个写入日志的是any,那么优先级是在同一时间点或者时间点冲突才会起作用
        //②如果第一个是high,那就是优先级会作用用整个队列
        //结果:第①种情况成立
    }

    /**
     * 测试环境中队列运行时,改变代码,是否会起作用
     */
    public function changeCode(){
        //测试环境中:listen中生效了.
        //queue:work在启动后，代码修改，queue:work不会再 Load 上下文，但是 queue:listen仍然会重新 Load 新代码。

        //使用 make:job LongQueue 新创建的队列来测试
        //这是一个会运行20秒的任务,访问两次,在第一次任务运行期间,改变代码,如果没有执行额外的指令,第二个任务是否会应用改变?
        $jobT = (new LongQueue('work指令的测试'))->onQueue('work');
        dispatch($jobT);
        //不会应用改变
        //测试:在同样访问两次,第一次进行期间,使用php artisan queue:restart 观察第一个任务是否中断,是否第二个任务应用了改变
        //结果:不会中断,但是队列进程已经不会继续执行第二个任务,未执行的任务仍然在数据库中(连接中),需要重新启动队列,并不会自动'重启'
        //重启的时机只要在执行queue:restart成功后就可以手动重启了,因为剩余队列还在连接中,正在执行的队列不会被取出,因此不会重复执行那个时机在运行的任务,不必等待

    }

    /**
     *
     */
    public function failQueue(){
        dispatch(new FailQueue());
    }

}
